﻿using Notoric.Commanding.CommandBase;

namespace Notoric.ViewModel
{
    /// <summary>
    /// An undoable command for creating a new barline segment.
    /// </summary>
    public class AddBarlineSegmentCommand : UndoableCommandBase
    {
        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="AddBarlineSegmentCommand"/> class.
        /// </summary>
        /// <param name="undoStack">The undo command stack</param>
        /// <param name="redoStack">The redo command stack</param>
        public AddBarlineSegmentCommand(CommandStack undoStack, CommandStack redoStack)
            : base(undoStack, redoStack)
        {
            AddParameter<Model.Elements.CWNotation.StaffDescriptor>("LowerStaff", ParameterDirection.In);
            AddParameter<Model.Elements.CWNotation.StaffDescriptor>("UpperStaff", ParameterDirection.In);

            AddParameter<Model.Elements.CWNotation.BarlineSegment>("CreatedSegment", ParameterDirection.Out);

            Name = "Create Barline Segment";
        }

        #endregion

        #region Command Logic

        /// <inheritdoc/>
        protected override void CommandOperation(object parameter)
        {
            var partData = LowerStaff.FindOwner<Model.Elements.CWNotation.CWPartData>();
            if (UpperStaff.FindOwner<Model.Elements.CWNotation.CWPartData>() != partData)
                throw new ExecutionException("The staves belong to different parts.");

            CreatedSegment = partData.AddBarlineSegment(UpperStaff, LowerStaff);

            CreatedSegment.PackagePart.Package.IsModified = true;
        }

        /// <inheritdoc/>
        protected override void RedoOperation()
        {
            CreatedSegment.FindOwner<Model.Elements.CWNotation.CWPartData>().BarlineSegments.Add(CreatedSegment);

            CreatedSegment.PackagePart.Package.IsModified = true;
        }

        /// <inheritdoc/>
        protected override void UndoOperation()
        {
            CreatedSegment.FindOwner<Model.Elements.CWNotation.CWPartData>().BarlineSegments.Remove(CreatedSegment);

            CreatedSegment.PackagePart.Package.IsModified = true;
        }

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets the created segment.
        /// </summary>
        /// <value>The created segment.</value>
        public Model.Elements.CWNotation.BarlineSegment CreatedSegment
        {
            get { return GetParameterValue<Model.Elements.CWNotation.BarlineSegment>("CreatedSegment"); }
            private set { SetParameterValue<Model.Elements.CWNotation.BarlineSegment>("CreatedSegment", value); }
        }

        /// <summary>
        /// Gets or sets the lower staff.
        /// </summary>
        /// <value>The lower staff.</value>
        public Model.Elements.CWNotation.StaffDescriptor LowerStaff
        {
            get { return GetParameterValue<Model.Elements.CWNotation.StaffDescriptor>("LowerStaff"); }
            set { SetParameterValue<Model.Elements.CWNotation.StaffDescriptor>("LowerStaff", value); }
        }

        /// <summary>
        /// Gets or sets the upper staff.
        /// </summary>
        /// <value>The upper staff.</value>
        public Model.Elements.CWNotation.StaffDescriptor UpperStaff
        {
            get { return GetParameterValue<Model.Elements.CWNotation.StaffDescriptor>("UpperStaff"); }
            set { SetParameterValue<Model.Elements.CWNotation.StaffDescriptor>("UpperStaff", value); }
        }

        #endregion
    }
}
